package com.example.manager;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.constant.ClientConstants;
import com.example.manager.bean.MHEARTBEAT;
import com.example.manager.bean.MHEARTMESS;
import com.example.manager.bean.MP2PT;
import com.example.manager.bean.MREG;
import com.example.manager.bean.MREGRESULT;
import com.example.manager.bean.MTOMANAGER;
import com.example.manager.bean.MTOT;
import com.example.receiver.TcpReceiver;
import com.example.receiver.UDPReceiver;
import com.example.terminal.bean.VMESS;
import com.example.type.StreamType;
import com.example.util.DataBuilder;
import com.example.util.Des;
import com.example.util.DeviceFactory;
import com.example.util.TcpRequestController;

public class ManagerClient {

	private final static Logger log = LoggerFactory.getLogger(ManagerClient.class);
			
	private static int no;
	
	protected String deviceId;
	
	protected String macid;
	
	/**
	 * 心跳socket
	 */
	protected DatagramSocket xt_sendsocket;
	
	/**
	 * 请求状态服务器socket
	 */
	protected DatagramSocket ask_sendsocket;
	
	/**
	 * 视频socket
	 */
	protected DatagramSocket p2p_v_sendsocket;
	
	/*** 音频socket */
	private DatagramSocket p2p_r_sendsocket;
	
	/**
	 * 后台数据库登录用户主键
	 */
	protected int userId;
	
	protected String internetIp;
	
	protected boolean shutdown = true;
	
	/*** t的公网ip */
	protected String nip;
	
	/*** m的固定的视频端口 */
	protected String vport = "";
	
	/*** m的固定的音频端口 */
	protected String rport = "";
	
//	/**
//	 * 命令线程超时时间
//	 */
//	protected int socketTimeout = 2000;
	
	/*** t的公网ip */
	protected String tip;
	
	/*** 接受视频的udp */
	protected UDPReceiver udpReceiver;
	
	protected TcpReceiver tcpReceiver;
	
	protected int times_v = 0, times_r = 0;
	
	public long receivedPakcages;
	
	public boolean stopAccept = false;
	
	protected static final int SOCKET_TIMEOUT = 30 * 1000;
	
	public ManagerClient(int socketTimeout, String macid) throws Exception {
		shutdown = false;
		deviceId = DeviceFactory.createDeviceId();
		macid = DataBuilder.buildLocalMacAddress();
		xt_sendsocket = new DatagramSocket();
		
		ask_sendsocket = new DatagramSocket();
		ask_sendsocket.setSoTimeout(socketTimeout);
		
//		p2p_v_sendsocket = new DatagramSocket(Integer.valueOf(vport));
		p2p_v_sendsocket = new DatagramSocket();
		p2p_v_sendsocket.setSoTimeout(socketTimeout);

//		p2p_r_sendsocket = new DatagramSocket(Integer.valueOf(rport));
		p2p_r_sendsocket = new DatagramSocket();
		p2p_r_sendsocket.setSoTimeout(socketTimeout);
		
		synchronized(this){
			no++;
		}
	}
	
	public ManagerClient(int socketTimeout) throws Exception {
		this(socketTimeout, DataBuilder.buildLocalMacAddress());
	}
	
	public ManagerClient(String macid) throws Exception {
		this(SOCKET_TIMEOUT, DataBuilder.buildLocalMacAddress());
	}
	
	public ManagerClient() throws Exception {
		this(SOCKET_TIMEOUT, DataBuilder.buildLocalMacAddress());
	}
	
	public void start() throws Exception {
		new XTThread().start();
		new XTREThread().start();
		startCommandSocket();
	}
	
	public void startCommandSocket() throws Exception {
		new O_Thread().start();
	}
	
	/**
	 * 
	 * @param phone	手机号
	 * @param password
	 * @param email
	 * @param tmac T端的mac地址（通过扫码获得）
	 */
	public MREGRESULT register(String phone, String password, String email) throws Exception {
		MREGRESULT result = new MREGRESULT();
		MREG reg = new MREG();
		reg.actiontype = "50";
		reg.musername = phone;
		reg.mpassword = password;
		reg.memail = email;
		reg.tmac = macid;
		
		Object data = TcpRequestController.GetResultByParam(reg, result,  ClientConstants.ip, ClientConstants.mport);
		result = (MREGRESULT)data;
		
		if(ClientConstants.Success.equals(result.result)){
			userId = Integer.valueOf(result.query);
			log.info("manager[{}] user id is {}", no, userId);
		}else{
			log.error("falied to register for user -> {}", phone);
		}
		
		
		return result;
	}
	
	public MREGRESULT login(String phone, String password){
		MREGRESULT result = new MREGRESULT();
		MREG reg = new MREG();
		reg.actiontype = "51";
		reg.musername = phone;
		reg.mpassword = password;
		result = (MREGRESULT)TcpRequestController.GetResultByParam(reg, result, ClientConstants.ip, ClientConstants.mport);	
		
		if(ClientConstants.Success.equals(result.result)){
			userId = Integer.valueOf(result.query);
			log.info("manager[{}] user id is {}", no, userId);
		}else{
			log.error("falied to login for user -> {}", phone);
		}
		
		return result; 
	}
	
	public MREGRESULT getInternetIp(){
		MREG reg = new MREG();
		reg.actiontype = "52";
		MREGRESULT result = new MREGRESULT();
		result = (MREGRESULT)TcpRequestController.GetResultByParam(reg, result, ClientConstants.ip, ClientConstants.mport);
		
		if(ClientConstants.Success.equals(result.result)){
			internetIp = result.query;
			log.info("manager[{}] internet ip is {}", no, internetIp);
		}else{
			log.error("falied to get internet ip");
		}
		
		return result;
	}
	
	public MREGRESULT changePassword(String phone, String oldPassword, String newPassword) throws Exception {
		MREGRESULT result = new MREGRESULT();
		MREG reg = new MREG();
		reg.actiontype = "53";
		reg.musername = phone;
		reg.oldpass = oldPassword;
		reg.mpassword = newPassword;
		result = (MREGRESULT)TcpRequestController.GetResultByParam(reg, result, ClientConstants.ip, ClientConstants.mport);
		
		log.info("change password result -> {}", result.content);
		
		return result;
	}
	
	public MREGRESULT addTerminal(int userId, String macId) throws Exception {
		MREGRESULT uid = new MREGRESULT();
		MTOT reg = new MTOT();
		reg.mcode = String.valueOf(userId);
		reg.tcode = macId;
		reg.actiontype = "54";
		return (MREGRESULT)TcpRequestController.GetResultByParam(reg, uid, ClientConstants.ip, ClientConstants.mtport);		
	}
	
	public MREGRESULT addTerminal(String macId) throws Exception {
		return addTerminal(userId, macId);		
	}
	
	public void getTerminalStatus(int mCode, int tCode) throws Exception {
		// TODO
	}
	
	public MREGRESULT removeTerminal(int tCode) throws Exception {
		return removeTerminal(userId, tCode);
	}
	
	public MREGRESULT removeTerminal(int mCode, int tCode) throws Exception {
		MREGRESULT uid = new MREGRESULT();
		MTOT reg = new MTOT();
		reg.mcode = String.valueOf(mCode);
		reg.tcode = String.valueOf(tCode);
		reg.actiontype = "55";
		return (MREGRESULT)TcpRequestController.GetResultByParam(reg, uid, ClientConstants.ip, ClientConstants.mtport);		
	}
	
	public void requestAVConnect(int tCode) throws Exception {
		requestAVConnect(userId, tCode);
	}
	
	public void requestAVConnect(int mCode, int tCode) throws Exception {
		MP2PT mp2pt = new MP2PT();
		mp2pt.actiontype = "2";
		mp2pt.mid = String.valueOf(mCode);
		mp2pt.tid = String.valueOf(tCode);
		String key = ClientConstants.key;
		String r = Des.encryptDES(DataBuilder.buildJson(mp2pt), key, key);
		DatagramPacket pack = new DatagramPacket(r.getBytes(), r.getBytes().length, InetAddress.getByName(ClientConstants.ip), 4114);
		
		ask_sendsocket.send(pack);
//		log.info("action", "第二步，M发送要请求的T的code给4114,t的code：{}", tCode);		
	}
	
	/**
	 * 请求中转管理服务器分配ip port
	 * @param mCode
	 * @param tCode
	 * @param contenttype 0 原功能;  1文件
	 * @throws Exception
	 */
	public void requestAVIPAndPort(int tCode, StreamType type) throws Exception {
		MTOMANAGER mtomanager = new MTOMANAGER();
		mtomanager.actiontype = "56";
		//原功能
		mtomanager.contenttype = type != StreamType.File ? "0" : String.valueOf(1);
		mtomanager.mt = userId + "_" + tCode;
		mtomanager.self = "M";
//		mtomanager.md5 = md5;
		String key = ClientConstants.key;
		String r = Des.encryptDES(DataBuilder.buildJson(mtomanager), key, key);
		DatagramPacket pack = new DatagramPacket(r.getBytes(), r.getBytes().length, InetAddress.getByName(ClientConstants.managerip), ClientConstants.managerport);
		ask_sendsocket.send(pack);
		log.debug("第四步，M给4120中转管理发消息，让他通知n和t");
	}
	
//	public void requestAVIPAndPort(int mCode, int tCode) throws Exception {
//		requestAVIPAndPort(mCode, tCode, null);
//	}
	
	public void requestAVIPAndPort(int tCode) throws Exception {
		requestAVIPAndPort(tCode, null);
	}
	
	public String acceptStream(StreamType streamType) throws Exception {
		while(udpReceiver == null){
			Thread.sleep(500);
		}
		return udpReceiver.accept(streamType, this);
	}
	
	public void acceptVedio(int mid, int no) throws Exception {
		while(udpReceiver == null){
			Thread.sleep(500);
		}
		udpReceiver.acceptVedio(mid, no);
	}
	
	public void acceptFile() throws Exception {
		while(tcpReceiver == null){
			Thread.sleep(500);
		}
		
		tcpReceiver.accept();
	}
	
	public void sendOrder(int type){
		switch(type){
			case 0://发送普通命令
				new Thread(){
					@Override
					public void run(){
						try {
							MHEARTBEAT temp = new MHEARTBEAT();
							temp.actiontype = "20";
							temp.mid = deviceId;
							temp.tid = "";
							temp.content = "dddd字符串";
							
							String xtjson;
							String key = ClientConstants.key;
							xtjson = Des.encryptDES(DataBuilder.buildJson(temp), key, key);
							DatagramPacket pack = new DatagramPacket(
									xtjson.getBytes(), xtjson.getBytes().length,
									InetAddress.getByName(ClientConstants.ip),ClientConstants.mxtport);
							xt_sendsocket.send(pack);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}.start();
				break;
			case 1://请求t发送文件过来
				//请求T端，获取文件
//				new Thread(){
//					@Override
//					public void run(){
//						reqFileTcp();
//					}
//				}.start();
				break;
		}
	}

	/*** 心跳发送线程 */
	public class XTThread extends Thread {
		@Override
		public void run() {
			try {
				MHEARTBEAT mheartbeat = new MHEARTBEAT();
				mheartbeat.actiontype = "1";
				mheartbeat.mid = deviceId;
				String key = ClientConstants.key;
				String xtjson = Des.encryptDES(DataBuilder.buildJson(mheartbeat), key, key);
				DatagramPacket pack = new DatagramPacket(xtjson.getBytes(), xtjson.getBytes().length, InetAddress.getByName(ClientConstants.ip), ClientConstants.mxtport);

				while (!shutdown) {
					try {
						if (mheartbeat != null && mheartbeat.mid != null && !mheartbeat.mid.equals("")) {
							xt_sendsocket.send(pack);
						}
						sleep(3000);
					} catch (Exception e) {
	
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/*** 心跳接收线程 */
	public class XTREThread extends Thread {
		@Override
		public void run() {
			while (!shutdown) {
				try {
					byte[] m_xbuffer;
					m_xbuffer = new byte[1500];
					DatagramPacket pack = new DatagramPacket(m_xbuffer, m_xbuffer.length);
					xt_sendsocket.receive(pack);
					MHEARTMESS mess = new MHEARTMESS();
					String key = ClientConstants.key;
					mess = DataBuilder.buildObject(Des.decryptDES(String.valueOf(new String(m_xbuffer)), key, key), mess);
					if (mess.actiontype.equals("-1")) {			//心跳返回
//						if (mess.tlist != null) {
//							MyApplication.getInstance().setTlst(mess.tlist);
//							Intent in = new Intent(); 
//							in.setAction("com.tlist");
//							MainActivityFragment.this.sendBroadcast(in); 
//						}
					}else if (mess.actiontype.equals("-2")) {	//
						if (mess.mid.equals(deviceId)) {
							log.info("manager[{}] 通知到下线了", no);
							shutdown = true;
						}
					}else if(mess.actiontype.equals("20")){
//						final String content = mess.content;
//						runOnUiThread(new Runnable(){
//							@Override
//							public void run() {
//								// TODO Auto-generated method stub
//								Toast.makeText(mine, content, Tips.TOAST).show();
//							}
//						});
						log.info("received text -> {}", mess.content);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/*** 命令线程 */
	public class O_Thread extends Thread {
		@Override
		public void run() {
			while (!shutdown) {
				try {
					byte[] o_buffer = new byte[300];
					DatagramPacket opack = new DatagramPacket(o_buffer, o_buffer.length);
//					log.info("prepare to receive command return value");
					
					ask_sendsocket.receive(opack);
					String s = new String(o_buffer);
					VMESS vmess = new VMESS();
					String key = ClientConstants.key;
					vmess = DataBuilder.buildObject(Des.decryptDES(String.valueOf(s), key, key), vmess);
					log.debug("tstate is {}", vmess.tstate);
					
					log.debug("manager received command return -> {}", vmess);
					
					// 如果是状态服务器s1发过来的消息
					if (opack.getAddress().toString().equals("/" + ClientConstants.ip)) {
						if (vmess.actiontype.equals("0")) { // 当M请求T的视频的时候，服务器返回来的状态信息
							
							if (vmess.tstate.equals("2")) {
								log.debug("第三步，M收到服务器给自己的t的状态");
//								exeRequest(7, null, null);
//								mMainHandler.sendEmptyMessage(2);
							} else if (vmess.tstate.equals("3")) {
//								mMainHandler.sendEmptyMessage(3);
							} else if (vmess.tstate.equals("4")) {
//								mMainHandler.sendEmptyMessage(4);
							}
						} else if (vmess.actiontype.equals("1")) { // 中转管理服务器向M或T发送N的ip和音视频端口
							log.debug("第五步，M收到4120回来的n的ip，端口等");
							nip = vmess.ip;
							vport = vmess.vport;
							rport = vmess.rport;
							String md5 = vmess.md5;
							if("1".equals(vmess.contenttype)){
								// 接受文件
								tcpReceiver = new TcpReceiver(nip, Integer.parseInt(vport), md5);
								log.info("created tcp receiver");
							}else{
								udpReceiver = new UDPReceiver(nip, Integer.parseInt(vport), Integer.parseInt(rport), p2p_v_sendsocket, p2p_r_sendsocket, 1);
							}
//							mMainHandler.sendEmptyMessage(8);
						}
					}
					
//					Thread.sleep(millis);
				} catch (Exception e) {
//					e.printStackTrace();
				}
			}
		}
	}

	/*** 视频线程 */
	class V_Thread extends Thread {
		@Override
		public void run() {
			while (!shutdown) {
				try {
					byte[] v_buffer = new byte[300];
					DatagramPacket vpack = new DatagramPacket(v_buffer, v_buffer.length);
					p2p_v_sendsocket.receive(vpack);
					
					String s = new String(v_buffer);
					VMESS vmess = new VMESS();
					String key = ClientConstants.key;
					vmess = DataBuilder.buildObject(Des.decryptDES(String.valueOf(s), key, key), vmess);

					log.debug("manager vedio thread received response -> {}", vmess);
					
					// 如果是服务器返回的数据
					if (vpack.getAddress().toString().equals("/" + ClientConstants.ip)) {
						// if (vmess.actiontype.equals("99")) { //
						// p2p中转，m请求t的时候返回来的t的状态
						// DatagramPacket temppack = new DatagramPacket(
						// "p2p_play_1".getBytes(),
						// "p2p_play_1".getBytes().length,
						// InetAddress.getByName(vmess.ip),
						// Integer.parseInt(vmess.rport));
						// p2p_v_sendsocket.send(temppack);
						// } else
						if (vmess.actiontype.equals("1")) {
							if (vmess.tstate.equals("2")) { // t空闲

							} else if (vmess.tstate.equals("3")) { // t忙碌

							} else if (vmess.tstate.equals("4")) { // t离线

							}
						} else if (vmess.actiontype.equals("2")) { // p2p中转，返回来的t的ip，端口
							tip = vmess.ip; // t的ip
							rport = vmess.rport; // t的端口
//							mMainHandler.sendEmptyMessage(5);
						}
						// 如果不是服务器返回的数据
					} else {
						// 局域网,m->t->m
						if (vmess.actiontype.equals("14")) {
							// 应该去新界面接收数据了
//							mMainHandler.sendEmptyMessage(8);
						} else if (vmess.actiontype.equals("12")) {
//							isConnect = true;
							VMESS tempvmess = new VMESS();
							tempvmess.actiontype = "13";
							String p2p_lan_sendt = Des.encryptDES(DataBuilder.buildJson(tempvmess), key, key);
							DatagramPacket temppack = new DatagramPacket(
									p2p_lan_sendt.getBytes(),
									p2p_lan_sendt.getBytes().length,
									vpack.getAddress(), vpack.getPort());
							p2p_v_sendsocket.send(temppack);
						} else if (vmess.actiontype.equals("3")) {
							// m和t处于不同局域网，尝试穿透
//							mMainHandler.sendEmptyMessage(7);
//							if (times_v == 0 || times_v == 1 || times_v == 2) {
//								VMESS temp = new VMESS();
//								temp.actiontype = "3";
//								String xtjson = Des.encryptDES(
//										son.toJson(temp), key, key);
//								DatagramPacket temppack = new DatagramPacket(
//										xtjson.getBytes(),
//										xtjson.getBytes().length,
//										vpack.getAddress(), vpack.getPort());
//								p2p_v_sendsocket.send(temppack);
//								if (times_v == 2) {
//									isConnect = true;
//									nip = tip;
//									vport = "" + vpack.getPort();
//									mMainHandler.sendEmptyMessage(8);
//								}
//							}
//							times_v++;
						}
					}
				} catch (Exception e) {

				}
			}
		}
	}
	
	/*** 音频线程 */
	class R_Thread extends Thread {
		@Override
		public void run() {
			while (!shutdown) {
				try {
					byte[] r_buffer = new byte[300];
					DatagramPacket rpack = new DatagramPacket(r_buffer, r_buffer.length);
					p2p_r_sendsocket.receive(rpack);
					String s = new String(r_buffer);
					String key = ClientConstants.key;
					
					VMESS vmess = new VMESS();
					vmess = DataBuilder.buildObject(Des.decryptDES(String.valueOf(s), key, key), vmess);

					// 如果是状态服务器s1发过来的消息
					if (rpack.getAddress().toString().equals("/" + ClientConstants.ip)) {
						if (vmess.actiontype.equals("1")) { // p2p中转，m请求t的时候返回来的t的状态
							if (vmess.tstate.equals("2")) { // t空闲
//								mMainHandler.sendEmptyMessage(2);
							} else if (vmess.tstate.equals("3")) { // t忙碌
//								mMainHandler.sendEmptyMessage(3);
							} else if (vmess.tstate.equals("4")) { // t离线
//								mMainHandler.sendEmptyMessage(4);
							}
						} else if (vmess.actiontype.equals("2")) { // p2p中转，返回来的t的ip，端口
							tip = vmess.ip; // t的ip
							rport = vmess.rport; // t的端口
//							mMainHandler.sendEmptyMessage(10);
						}
					} else {
						if (vmess.actiontype.equals("3")) {
//							mMainHandler.sendEmptyMessage(7);
							if (times_r == 0 || times_r == 1 || times_r == 2) {
								VMESS temp = new VMESS();
								temp.actiontype = "3";
								String xtjson = Des.encryptDES(DataBuilder.buildJson(temp), key, key);
								DatagramPacket temppack = new DatagramPacket(
										xtjson.getBytes(),
										xtjson.getBytes().length,
										rpack.getAddress(), rpack.getPort());
								p2p_r_sendsocket.send(temppack);
								rport = "" + rpack.getPort();
							}
							times_r++;
						}
					}
				} catch (Exception e) {

				}
			}
		}
	}

	public int getUserId() {
		return userId;
	}

	public void setUserId(int userId) {
		this.userId = userId;
	}

	public static int getNo() {
		return no;
	}

}
